home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Just Call Me Internet
/
Just Call Me Internet.iso
/
prog
/
atari
/
c
/
du_lib
/
textedit.c
< prev
next >
Wrap
C/C++ Source or Header
|
1995-07-10
|
32KB
|
1,021 lines
/*
DU_LIB v2
Gem Window Management & Dialog Library For Lattice C
½1994,1995 by Craig Graham.
Based on the DU_LIBv1 Library for HiSoft Basic.
*/
/*
Text Edit Widget
This provides a full text editor with scrolling & mouse click/drag selection
and GEM clipboard support. If the cut & paste routines look a little inefficient,
it's because they are intended to allow external access to the cut paste functions
as well as the standard keyboard shortcuts (^X,^C,^V).
*/
#include "DULIB.H"
#include <stdio.h>
/* Create a text widget */
void Set_text_widget(short dialog, short ob, short max_columns, short max_lines)
{
text_line *tln_t;
Elist *n;
Set_object_Kcallback(dialog, ob, &TW_keypress); // Install Object Layer keyhandler
Set_object_callback(dialog, ob, &TW_mouse_click); // Install a callback to handle mouse clicks
Set_object_redraw(dialog, ob, &TW_display); // Setup a redraw function
if (find_event(dialog,ob,&n)) // There be an event structure for the widget by now - if there isn't then we've got problems
{
n->wtext.max_lines=max_lines;
n->wtext.max_columns=max_columns;
n->wtext.current_column=0;
n->wtext.cursor_y=0;
tln_t=(text_line*)malloc(sizeof(text_line)); // Create initial line
tln_t->the_text=(char*)malloc(sizeof(char)*max_columns);
tln_t->the_text[0]='\0';
tln_t->eof_line=0; // initially nothing on the line
tln_t->prev=NULL; // No lines before this
tln_t->next=NULL; // No lines after this
n->wtext.current_line=tln_t; // Initial cursor position == top line.
n->wtext.display_baseline=tln_t; // Initial display baseline == top line.
n->wtext.sel_start_line=n->wtext.sel_end_line=NULL; // Initially, no text selected
}else{
form_alert(1,"[1][ ERROR: Unable to create text widget. ][ Bugger ]");
}
}
/*
Change/initialise all the text in a text widget
This allows you to load text into a text widget.
*/
void Change_widget_text(short dialog, short ob, char *t[], short lines)
{
Elist *n;
text_line *tln, *tln_t;
short sl,l,max_columns;
if (find_event(dialog,ob,&n))
{
tln=n->wtext.text; // Dispose of the current text widget contents
while(tln) {
tln_t=tln;
tln=tln->next;
free(tln_t->the_text); //free up the char array.
free(tln_t); //free up the line structure
}
n->wtext.text=NULL;
n->wtext.current_column=0;
n->wtext.cursor_y=0;
n->wtext.sel_start_line=n->wtext.sel_end_line=NULL; // No text selected
if ((lines>n->wtext.max_lines)&&(n->wtext.max_lines>0))
{
lines=n->wtext.max_lines;
}
max_columns=n->wtext.max_columns;
for (l=0; l<lines; l++) // Find the maximum number of columns used
{
sl=strlen(t[l]);
if (sl>max_columns) max_columns=sl;
}
max_columns++;
n->wtext.max_columns=max_columns;
tln_t=(text_line*)malloc(sizeof(text_line)); // Create initial line
tln_t->the_text=(char*)malloc(sizeof(char)*max_columns);
tln_t->the_text[0]='\0';
tln_t->eof_line=0; // initially nothing on the line
tln_t->prev=NULL; // No lines before this
n->wtext.current_line=tln_t; // Initial cursor position == top line.
n->wtext.display_baseline=tln_t; // Initial display baseline == top line.
n->wtext.text=tln_t;
for (l=0; l<lines; l++)
{
tln=tln_t;
sprintf(tln->the_text,"%s",t[l]); // Copy the text into the line entry
tln->eof_line=strlen(t[l]);
tln_t=(text_line*)malloc(sizeof(text_line));
tln_t->the_text=(char*)malloc(sizeof(char)*max_columns);
tln->next=tln_t;
tln_t->prev=tln;
}
free(tln_t); // Loop creates one to many entries :(
tln->next=NULL;
}else{
form_alert(1,"[1][ ERROR: Cann't find text widget info. ][ Bugger ]");
}
}
/*
Get all the text in a text widget
This will dispose of the current contents of a char *t[] array if text_lines
is passed
*/
short Get_widget_text(short dialog, short ob, char ***text, short text_lines)
{
Elist *n;
text_line *tln;
char **txt;
short number_of_lines,l;
if (find_event(dialog,ob,&n))
{
if (text_lines) // Dispose of current text
{
txt=*text;
for(l=0; l<text_lines; l++) free(txt[l]);
free(txt);
}
tln=n->wtext.text; // Count up the number of lines
for(number_of_lines=0; tln; number_of_lines++) tln=tln->next;
number_of_lines++;
txt=(char**)malloc(sizeof(char*)*number_of_lines);
*text=txt;
l=0; tln=n->wtext.text;
do {
txt[l]=(char*)malloc(sizeof(char)*(tln->eof_line+1));
sprintf(txt[l],"%s",tln->the_text);
l++; tln=tln->next;
} while (tln);
return number_of_lines;
}else{
form_alert(1,"[1][ ERROR: Cann't find text widget info. ][ Bugger ]");
}
}
/*
Display the text cursor for a given text widget
*/
void TW_display_cursor(short dialog, short ob)
{
Elist *n;
short ch,cw;
short pts[8];
short dlx,dly;
if (find_event(dialog,ob,&n))
{
vsf_color(x_handle,1); vsf_interior(x_handle,FIS_SOLID); vsf_perimeter(x_handle,0);
vswr_mode(x_handle, MD_XOR);
vqt_extent(x_handle,"A",pts);
ch=abs(pts[1]-pts[7]); // Height of one character in current font
cw=abs(pts[0]-pts[2]); // Width of one character in current font
dlx=cr_clip.g_x+5+cw*n->wtext.current_column; dly=cr_clip.g_y+8+ch*n->wtext.cursor_y;
pts[0]=dlx; pts[2]=dlx+cw-1;
pts[1]=dly; pts[3]=dly+ch-1;
v_bar(x_handle,pts);
vswr_mode(x_handle, MD_REPLACE);
}
}
/*
Display a highlighted (ie. selected) region in a text
widget.
*/
void TW_display_highlighted(short dialog, short ob)
{
Elist *n;
text_line *tln_t,*tl,*de_l,*ds_l;
short ch,cw,l;
short pts[8];
short dlx,dly;
short sx, sy, ex, ey;
if (find_event(dialog,ob,&n))
{
vsf_color(x_handle,1); vsf_interior(x_handle,FIS_SOLID); vsf_perimeter(x_handle,0);
vswr_mode(x_handle, MD_XOR);
vqt_extent(x_handle,"A",pts);
ch=abs(pts[1]-pts[7]); // Height of one character in current font
cw=abs(pts[0]-pts[2]); // Width of one character in current font
tl=n->wtext.display_baseline;
ds_l=de_l=NULL;
sy=ey=-1;
for(l=0; (l<n->wtext.display_lines_high)&&(tl->next!=NULL); tl=tl->next )
{
if (tl==n->wtext.sel_start_line)
{
ds_l=tl;
sx=n->wtext.sel_start_char;
sy=l;
}
if (tl==n->wtext.sel_end_line)
{
de_l=tl;
ex=n->wtext.sel_end_char;
ey=l;
}
l++;
}
if (ds_l==NULL)
{
ds_l=n->wtext.display_baseline;
sx=sy=0;
}
if (de_l==NULL)
{
de_l=tl;
ex=tl->eof_line;
ey=l-1;
}
if (sy==ey) // mark only on a single line
{
dlx=cr_clip.g_x+5+cw*sx; dly=cr_clip.g_y+8+ch*sy;
pts[0]=dlx; pts[2]=dlx+cw*(ex-sx)-1;
pts[1]=dly; pts[3]=dly+ch-1;
v_bar(x_handle,pts);
}else{ // mark split over two or more lines
dlx=cr_clip.g_x+5+cw*sx; dly=cr_clip.g_y+8+ch*sy; // display last line (start_char .. end of line)
pts[0]=dlx; pts[2]=dlx+cw*(ds_l->eof_line-sx)-1;
pts[1]=dly; pts[3]=dly+ch-1;
v_bar(x_handle,pts);
tln_t=ds_l; // display middle bit (fully selected lines) - if any
pts[0]=cr_clip.g_x+5;
for(l=sy+1; l<ey; l++)
{
tln_t=tln_t->next;
pts[2]=pts[0]+cw*tln_t->eof_line-1;
pts[1]=cr_clip.g_y+8+ch*l;; pts[3]=pts[1]+ch-1;
v_bar(x_handle,pts);
}
dlx=cr_clip.g_x+5; dly=cr_clip.g_y+8+ch*ey; // display last line (start of line .. end_char)
pts[0]=dlx; pts[2]=dlx+cw*ex+1;
pts[1]=dly; pts[3]=dly+ch-1;
v_bar(x_handle,pts);
}
vswr_mode(x_handle, MD_REPLACE);
}
}
/*
Text Widget Display Routine
*/
short TW_display(void)
{
Elist *n;
char cursor[2];
short de,l,ch,cw;
short pts[8];
short dlx,dly,f;
text_line *tl;
if (find_event(this_dialog,this_ob,&n))
{
vst_color(x_handle,1); vst_point(x_handle,10,&junk,&junk,&junk,&junk);
vst_rotation(x_handle,0); vst_alignment(x_handle,0,0,wm_inv,wm_outv);
vsf_interior(x_handle,FIS_SOLID); vsf_perimeter(x_handle,0);
vswr_mode(x_handle, MD_TRANS);
vsf_color(x_handle,0);
pts[0]=cr_clip.g_x+1; pts[2]=pts[0]+cr_clip.g_w-2;
pts[1]=cr_clip.g_y+1; pts[3]=pts[1]+cr_clip.g_h-2;
v_bar(x_handle,pts);
vsf_color(x_handle,1);
vqt_extent(x_handle,"A",pts);
ch=abs(pts[1]-pts[7]); // Height of one character in current font
cw=abs(pts[0]-pts[2]); // Width of one character in current font
cursor[1]='\0';
n->wtext.display_lines_high=(short)(cr_clip.g_h/ch) - 1; // fill in this each time, just 'coz it's easy to calculate here
de=cr_clip.g_y+cr_clip.g_h-5;
tl=n->wtext.display_baseline;
if (tl)
{
dlx=cr_clip.g_x+5; l=0;
for(dly=cr_clip.g_y+ch+5; (dly<de)&&(tl!=NULL); dly=dly+ch)
{
v_gtext(x_handle, dlx, dly, tl->the_text); // display the text line
tl=tl->next;
}
vswr_mode(x_handle, MD_XOR);
dlx=cr_clip.g_x+5+cw*n->wtext.current_column; dly=cr_clip.g_y+8+ch*n->wtext.cursor_y;
pts[0]=dlx; pts[2]=dlx+cw-1;
pts[1]=dly; pts[3]=dly+ch-1;
v_bar(x_handle,pts);
vswr_mode(x_handle, MD_REPLACE);
}
/* Highlight any selected text which is currently displayed */
if ((n->wtext.sel_start_line!=NULL)&&(n->wtext.sel_end_line!=NULL))
{
if ((n->wtext.sel_start_line!=n->wtext.sel_end_line)||(n->wtext.sel_start_char!=n->wtext.sel_end_char))
{
tl=n->wtext.display_baseline; f=FALSE;
for(l=0; (l<n->wtext.display_lines_high)&&(tl->next!=NULL); tl=tl->next )
{
if ((tl==n->wtext.sel_start_line)||(tl==n->wtext.sel_end_line)) f=TRUE;
l++;
}
if (!f) // No selection markers found in display at all, check to see if whole display is selected
{
tl=n->wtext.sel_start_line;
for(l=0; (l<n->wtext.display_lines_high)&&(tl->next!=NULL); tl=tl->next )
{
if (tl==n->wtext.display_baseline) // If we find the display baseline in the selected text, then the whole display is selected
f=TRUE;
l++;
}
}
if (f) TW_display_highlighted(this_dialog, this_ob);
}
}
}else{
form_alert(1,"[1][ ERROR: Cann't find text widget info. ][ Bugger ]");
}
return TRUE;
}
/*
Text Widget mouse click handler
*/
short TW_mouse_click(void)
{
Elist *n;
text_line *tln_t,*tl;
short ch,cw,x,y,rx,ry,l,mb,rl_x,rl_y,lrl_x,lrl_y,e;
short f;
short pts[8];
graf_mkstate(&lrl_x,&lrl_y,&mb,&junk);
if (find_event(this_dialog,this_ob,&n))
{
vqt_extent(x_handle,"A",pts);
ch=abs(pts[1]-pts[7]); // Height of one character in current font
cw=abs(pts[0]-pts[2]); // Width of one character in current font
x=(short)((cr_mx-5/2)/cw); // Click position in terms of characters & lines
y=(short)((cr_my-5)/ch); if (y<0) y=0;
if (mb==0)
{
graf_mouse(M_OFF,NULL); // Un-display the old cursor
TW_display_cursor(this_dialog, this_ob);
n->wtext.current_line=n->wtext.display_baseline;
for(l=0; (n->wtext.current_line->next!=NULL)&&(l<y); l++)
n->wtext.current_line=n->wtext.current_line->next;
n->wtext.cursor_y=l;
if (x>n->wtext.current_line->eof_line)
n->wtext.current_column=n->wtext.current_line->eof_line;
else
n->wtext.current_column=x;
TW_display_cursor(this_dialog, this_ob); // Display new cursor position
graf_mouse(M_ON,NULL);
}else{
/* First, erase the current selection if there is one */
if ((n->wtext.sel_start_line!=NULL)&&(n->wtext.sel_end_line!=NULL))
{
if ((n->wtext.sel_start_line!=n->wtext.sel_end_line)||(n->wtext.sel_start_char!=n->wtext.sel_end_char))
{
tl=n->wtext.display_baseline; f=FALSE;
for(l=0; (l<n->wtext.display_lines_high)&&(tl->next!=NULL); tl=tl->next )
{
if ((tl==n->wtext.sel_start_line)||(tl==n->wtext.sel_end_line))
f=TRUE;
l++;
}
if (!f) // No selection markers found in display at all, check to see if whole display is selected
{
tl=n->wtext.sel_start_line;
for(l=0; (l<n->wtext.display_lines_high)&&(tl->next!=NULL); tl=tl->next )
{
if (tl==n->wtext.display_baseline) // If we find the display baseline in the selected text, then the whole display is selected
f=TRUE;
l++;
}
}
if (f)
{
graf_mouse(M_OFF,NULL);
TW_display_highlighted(this_dialog, this_ob);
graf_mouse(M_ON,NULL);
}
}
}
/* Now, find the start line for the new selected text */
n->wtext.sel_start_line=n->wtext.display_baseline;
for(l=0; (n->wtext.sel_start_line->next!=NULL)&&(l<y); l++)
n->wtext.sel_start_line=n->wtext.sel_start_line->next;
if (n->wtext.sel_start_line->next==NULL) y=l;
if (x>n->wtext.sel_start_line->eof_line)
{
x=n->wtext.sel_start_char=n->wtext.sel_start_line->eof_line;
}else
n->wtext.sel_start_char=x;
rx=x; ry=y;
do
{
e=evnt_multi(MU_BUTTON|MU_M1,1,1,1,
1,lrl_x,lrl_y,1,1,
0,0,0,0,0,
messB,1,0,&rl_x,&rl_y,&mb,&junk,&junk,&junk);
graf_mkstate(&junk,&junk,&mb,&junk);
if (e&MU_M1)
{
graf_mouse(M_OFF,NULL);
if ((rx!=x)||(ry!=y)) // Erase the current highlight
TW_display_highlighted(this_dialog, this_ob);
rx=(rl_x-cr_clip.g_x-5)/cw;
ry=(rl_y-cr_clip.g_y-5)/ch;
if (ry<=y) // Can only mark forwards using this :(
{
ry=y;
if (rx<x) rx=x;
}
tln_t=n->wtext.display_baseline; // Find the line containing the end marker
for (l=0; (tln_t->next!=NULL)&&(l<ry); l++) tln_t=tln_t->next;
n->wtext.sel_end_line=tln_t;
if (tln_t->next==NULL) ry=l;
if (rx>tln_t->eof_line) // Make sure we cann't select past eofline
{
rx=n->wtext.sel_end_char=tln_t->eof_line;
}else
n->wtext.sel_end_char=rx;
if ((rx!=x)||(ry!=y)) // Display the new highlight
TW_display_highlighted(this_dialog, this_ob);
graf_mouse(M_ON,NULL);
lrl_x=rl_x; lrl_y=rl_y;
}
} while (mb);
}
}
return FALSE;
}
/*
Copy selected text to the GEM clipboard
*/
void TW_copy_text(short dialog, short object)
{
Elist *n;
FILE *scrap_file;
text_line *tt;
text_line *tn;
char p[FMSIZE+10];
char *c, *tmp;
if (find_event(dialog,object,&n))
{
sprintf(p,"%s%s",clipboard_path,"SCRAP.TXT");
scrap_file=fopen(p,"w");
if (scrap_file)
{
tmp=(char*)malloc(sizeof(char)*(n->wtext.max_columns+3));
c=n->wtext.sel_start_line->the_text + n->wtext.sel_start_char;
sprintf(tmp,"%s",c);
if (n->wtext.sel_start_line==n->wtext.sel_end_line)
tmp[n->wtext.sel_end_char - n->wtext.sel_start_char]='\0';
fprintf(scrap_file,"%s\n",tmp);
if (n->wtext.sel_start_line!=n->wtext.sel_end_line)
{
tt=n->wtext.sel_start_line->next; tn=n->wtext.sel_end_line;
while (tt!=tn)
{
fprintf(scrap_file,"%s\n",tt->the_text);
tt=tt->next;
}
sprintf(tmp,"%s",n->wtext.sel_end_line->the_text);
tmp[n->wtext.sel_end_char]='\0';
fprintf(scrap_file,"%s\n",tmp);
}
fclose(scrap_file);
free(tmp);
}else{
form_alert(1,"[1][ ERROR: Cann't write to clipboard. ][ Bugger ]");
}
}else{
form_alert(1,"[1][ ERROR: Cann't find text widget info. ][ Bugger ]");
}
}
/*
Cut selected text to the GEM clipboard
*/
void TW_cut_text(short dialog, short object)
{
Elist *n;
text_line *tl, *tln;
char *tmp,*t1,*t2;
TW_copy_text(dialog, object); // First, copy the text to the clipboard
if (find_event(dialog, object,&n))
{
tmp=(char*)malloc(sizeof(char)*(n->wtext.max_columns+4));
if (n->wtext.sel_start_line!=n->wtext.sel_end_line) // Delete text from first line
{
n->wtext.sel_start_line->the_text[n->wtext.sel_start_char]='\0';
}else{
sprintf(tmp,"%s",n->wtext.sel_start_line->the_text);
t1=n->wtext.sel_start_line->the_text + n->wtext.sel_end_char;
t2=tmp+n->wtext.sel_start_char;
sprintf(t2,"%s",t1);
sprintf(n->wtext.sel_start_line->the_text,"%s",tmp);
}
n->wtext.sel_start_line->eof_line=strlen(n->wtext.sel_start_line->the_text);
if (n->wtext.sel_start_line!=n->wtext.sel_end_line) // Delete whole lines that are going
{
tl=n->wtext.sel_start_line->next;
while (tl!=n->wtext.sel_end_line)
{
tln=tl->next;
free(tl->the_text);
free(tl);
tl=tln;
}
n->wtext.sel_start_line->next=n->wtext.sel_end_line;
t1=n->wtext.sel_end_line->the_text + n->wtext.sel_end_char; // Delete start of last line
sprintf(tmp,"%s",t1);
sprintf(n->wtext.sel_end_line->the_text,"%s",tmp);
}
n->wtext.sel_end_line=n->wtext.sel_start_line;
n->wtext.sel_end_char=n->wtext.sel_start_char=0;
free(tmp);
}else{
form_alert(1,"[1][ ERROR: Cann't find text widget info. ][ Bugger ]");
}
}
/*
The Text Widget Keyboard Handler
The TWKH runs as an Object Layer key handler associated with text widget objects.
This copes with all the standard text editting CTRL+key combo's, those which aren't
recognised are dropped through to the Dialog Layer.
All ALT+key combos are dropped through to the Dialog Layer.
This is pretty messy - don't laugh, at least it works.
*/
short TW_keypress(void)
{
Elist *n;
text_line *tln_t;
char c, *tmp;
short p,f;
if (!find_event(this_dialog,this_ob,&n))
{
form_alert(1,"[1][ ERROR: Cann't find text widget info. ][ Bugger ]");
return FALSE;
}
if (kc_shstate&K_ALT) // Text widgets don't use ALT+key combo's
return FALSE; // so let the key through to Dialog Layer.
if (kc_shstate&K_CTRL) // Is control held down? If so, there may be a CTRL+key combo we want to know about.
{
switch (kc_key) // Do plain cursor & special key parsing
{
case 0x2e03: // ^C==Copy
if ((n->wtext.sel_start_line!=n->wtext.sel_end_line)||(n->wtext.sel_start_char!=n->wtext.sel_end_char))
{
TW_copy_text(this_dialog, this_ob);
}
return TRUE;
break;
case 0x2d18: // ^X==Cut
if ((n->wtext.sel_start_line!=n->wtext.sel_end_line)||(n->wtext.sel_start_char!=n->wtext.sel_end_char))
{
TW_cut_text(this_dialog, this_ob);
graf_mouse(M_OFF,NULL);
TW_display();
graf_mouse(M_ON,NULL);
}
return TRUE;
break;
}
return FALSE; // Allow any CTRL+key combo's that the text_widget doesn't understand fall through to the Dialog layer.
}
switch (kc_key) // Do plain cursor & special key parsing
{
case 0x4800: // Cursor up
if (n->wtext.current_line->prev)
{
if (n->wtext.cursor_y)
{
graf_mouse(M_OFF,NULL);
TW_display_cursor(this_dialog, this_ob);
n->wtext.current_line=n->wtext.current_line->prev;
n->wtext.cursor_y--;
if (n->wtext.current_column>n->wtext.current_line->eof_line)
n->wtext.current_column=n->wtext.current_line->eof_line;
TW_display_cursor(this_dialog, this_ob);
graf_mouse(M_ON,NULL);
}else{
n->wtext.display_baseline=n->wtext.current_line=n->wtext.current_line->prev;
if (n->wtext.current_column>n->wtext.current_line->eof_line)
n->wtext.current_column=n->wtext.current_line->eof_line;
graf_mouse(M_OFF,NULL);
TW_display();
graf_mouse(M_ON,NULL);
}
}
return TRUE; // Consume
break;
case 0x4838: // Shift+Cursor up
for (f=0; (f<n->wtext.display_lines_high)&&(n->wtext.display_baseline->prev!=NULL); f++)
{
n->wtext.display_baseline=n->wtext.display_baseline->prev;
n->wtext.current_line=n->wtext.current_line->prev;
}
if (n->wtext.current_column>n->wtext.current_line->eof_line)
n->wtext.current_column=n->wtext.current_line->eof_line;
graf_mouse(M_OFF,NULL);
TW_display();
graf_mouse(M_ON,NULL);
return TRUE; // Consume
break;
case 0x5000: // Cursor down
if (n->wtext.current_line->next)
{
if (n->wtext.cursor_y<n->wtext.display_lines_high-1)
{
graf_mouse(M_OFF,NULL);
TW_display_cursor(this_dialog, this_ob);
n->wtext.current_line=n->wtext.current_line->next;
n->wtext.cursor_y++;
if (n->wtext.current_column>n->wtext.current_line->eof_line)
n->wtext.current_column=n->wtext.current_line->eof_line;
TW_display_cursor(this_dialog, this_ob);
graf_mouse(M_ON,NULL);
}else{
n->wtext.display_baseline=n->wtext.display_baseline->next;
n->wtext.current_line=n->wtext.current_line->next;
if (n->wtext.current_column>n->wtext.current_line->eof_line)
n->wtext.current_column=n->wtext.current_line->eof_line;
graf_mouse(M_OFF,NULL);
TW_display();
graf_mouse(M_ON,NULL);
}
}
return TRUE; // Consume
break;
case 0x5032: // Shift+Cursor down
for (f=0; (f<n->wtext.display_lines_high)&&(n->wtext.current_line->next!=NULL); f++)
{
n->wtext.display_baseline=n->wtext.display_baseline->next;
n->wtext.current_line=n->wtext.current_line->next;
}
if (n->wtext.current_column>n->wtext.current_line->eof_line)
n->wtext.current_column=n->wtext.current_line->eof_line;
graf_mouse(M_OFF,NULL);
TW_display();
graf_mouse(M_ON,NULL);
return TRUE; // Consume
break;
case 0x4d00: // Cursor right
if (n->wtext.current_column<n->wtext.current_line->eof_line) // If we aren't at RHS, step right one character
{
graf_mouse(M_OFF,NULL);
TW_display_cursor(this_dialog, this_ob);
n->wtext.current_column++;
TW_display_cursor(this_dialog, this_ob);
graf_mouse(M_ON,NULL);
}else{ // Otherwise, try to go to start of next line
if (n->wtext.current_line->next)
{
if (n->wtext.cursor_y<n->wtext.display_lines_high-1)
{
graf_mouse(M_OFF,NULL);
TW_display_cursor(this_dialog, this_ob);
n->wtext.current_column=0;
n->wtext.current_line=n->wtext.current_line->next;
n->wtext.cursor_y++;
TW_display_cursor(this_dialog, this_ob);
graf_mouse(M_ON,NULL);
}else{
n->wtext.current_column=0;
n->wtext.display_baseline=n->wtext.display_baseline->next;
n->wtext.current_line=n->wtext.current_line->next;
graf_mouse(M_OFF,NULL);
TW_display();
graf_mouse(M_ON,NULL);
}
}
}
return TRUE; // Consume
break;
case 0x4d36: // Shift+Cursor right
if (n->wtext.current_column<n->wtext.current_line->eof_line)
{
n->wtext.current_column=n->wtext.current_line->eof_line;
graf_mouse(M_OFF,NULL);
TW_display();
graf_mouse(M_ON,NULL);
}
return TRUE; // Consume
break;
case 0x4b00: // Cursor left
if (n->wtext.current_column>0) // If we aren't at LHS, just step left
{
graf_mouse(M_OFF,NULL);
TW_display_cursor(this_dialog, this_ob);
n->wtext.current_column--;
TW_display_cursor(this_dialog, this_ob);
graf_mouse(M_ON,NULL);
}else{ // Otherwise, try to go to EOF previous line
if (n->wtext.current_line->prev)
{
if (n->wtext.cursor_y)
{
graf_mouse(M_OFF,NULL);
TW_display_cursor(this_dialog, this_ob);
n->wtext.current_line=n->wtext.current_line->prev;
n->wtext.cursor_y--;
n->wtext.current_column=n->wtext.current_line->eof_line;
TW_display_cursor(this_dialog, this_ob);
graf_mouse(M_ON,NULL);
}else{
n->wtext.display_baseline=n->wtext.current_line=n->wtext.current_line->prev;
n->wtext.current_column=n->wtext.current_line->eof_line;
graf_mouse(M_OFF,NULL);
TW_display();
graf_mouse(M_ON,NULL);
}
}
}
return TRUE; // Consume
break;
case 0x4b34: // Shift+Cursor left
if (n->wtext.current_column>0)
{
n->wtext.current_column=0;
graf_mouse(M_OFF,NULL);
TW_display();
graf_mouse(M_ON,NULL);
}
return TRUE; // Consume
break;
case 0x4700: // Clear home
n->wtext.display_baseline=n->wtext.current_line=n->wtext.text;
n->wtext.current_column=0;
n->wtext.cursor_y=0;
graf_mouse(M_OFF,NULL);
TW_display();
graf_mouse(M_ON,NULL);
return TRUE; // Consume
break;
case 0x4737: // Shift+Clear Home == bottom of text
for (; n->wtext.current_line->next!=NULL; )
{
n->wtext.display_baseline=n->wtext.display_baseline->next;
n->wtext.current_line=n->wtext.current_line->next;
}
if (n->wtext.current_column>n->wtext.current_line->eof_line)
n->wtext.current_column=n->wtext.current_line->eof_line;
graf_mouse(M_OFF,NULL);
TW_display();
graf_mouse(M_ON,NULL);
return TRUE; // Consume
break;
case 0x1c0d: // Enter inserts a new line
tln_t=(text_line*)malloc(sizeof(text_line)); // Allocate a new line
tln_t->the_text=(char*)malloc(sizeof(char)*n->wtext.max_columns); // Text store for the new line
tln_t->the_text[0]='\0'; // Flag the text store as initially empty
tln_t->next=n->wtext.current_line->next; // Slot the new line into the lines list for this widget
n->wtext.current_line->next=tln_t;
tln_t->prev=n->wtext.current_line;
if (tln_t->next) tln_t->next->prev=tln_t; // If we aren't last line in the list, ensure the next line know where we are.
if (n->wtext.current_column!=n->wtext.current_line->eof_line) // If not at end of line, move the rest of the current line onto a new line
{
tmp=n->wtext.current_line->the_text+(n->wtext.current_column);
sprintf(tln_t->the_text,"%s",tmp);
n->wtext.current_line->the_text[n->wtext.current_column]='\0';
n->wtext.current_line->eof_line=n->wtext.current_column;
}
tln_t->eof_line=strlen(tln_t->the_text); // Where is end of line?
n->wtext.current_line=tln_t; // Current line == the new line
n->wtext.current_column=0; // Always begin with cursor at start of new line
if (n->wtext.cursor_y<n->wtext.display_lines_high-1) // Insert a new line not at bottom of widget, move cursor down a line
{
n->wtext.cursor_y++;
}else{ // Otherwise, scroll the whole widget up one line & leave cursor at same posistion
n->wtext.display_baseline=n->wtext.display_baseline->next;
}
graf_mouse(M_OFF,NULL);
TW_display();
graf_mouse(M_ON,NULL);
return TRUE; // Consume
break;
case 0x0e08: // Backspace
if (n->wtext.current_column>0) // If we aren't at LHS, just copy over char directly to our left
{
for(p=n->wtext.current_column-1; p<n->wtext.current_line->eof_line; p++)
n->wtext.current_line->the_text[p]=n->wtext.current_line->the_text[p+1];
n->wtext.current_column--;
n->wtext.current_line->eof_line--;
n->wtext.current_line->the_text[n->wtext.current_line->eof_line]='\0';
graf_mouse(M_OFF,NULL);
TW_display();
graf_mouse(M_ON,NULL);
}else{ // Otherwise, try to go to EOF previous line
if (n->wtext.current_line->prev)
{
if (n->wtext.current_line->eof_line+n->wtext.current_line->prev->eof_line < n->wtext.max_columns)
{
tln_t=n->wtext.current_line;
tmp=tln_t->prev->the_text+(tln_t->prev->eof_line); // Tag line onto the end off previous line
sprintf(tmp,"%s",tln_t->the_text);
n->wtext.current_column=tln_t->prev->eof_line;
tln_t->prev->eof_line=strlen(tln_t->prev->the_text);
tln_t->prev->the_text[tln_t->prev->eof_line]='\0';
tln_t->prev->next=tln_t->next; // detatch line from list
if (tln_t->next)
tln_t->next->prev=tln_t->prev;
if (n->wtext.display_baseline==tln_t) n->wtext.display_baseline=n->wtext.current_line->prev;
n->wtext.current_line=n->wtext.current_line->prev;
free(tln_t->the_text); //free up the char array.
free(tln_t); //free up the line structure
if (n->wtext.cursor_y)
n->wtext.cursor_y--;
graf_mouse(M_OFF,NULL);
TW_display();
graf_mouse(M_ON,NULL);
}
}
}
return TRUE; // Consume
break;
case 0x537f: // Delete
if (kc_shstate&(K_RSHIFT|K_LSHIFT)) // Shift Delete does delete line
{
tln_t=n->wtext.current_line;
if (tln_t->prev)
tln_t->prev->next=tln_t->next; // detatch line from list
if (tln_t->next)
tln_t->next->prev=tln_t->prev;
if (tln_t->next) // If there is a next line, shift it up to be under the cursor
{
n->wtext.current_line=tln_t->next;
}else{
if (tln_t->prev) // Otherwise go back to previous line
{
n->wtext.current_line=tln_t->prev;
if (n->wtext.cursor_y) // If not at top of widget, move cursor up a line.
n->wtext.cursor_y--;
}
}
if (n->wtext.display_baseline==tln_t) // If the baseline has been deleted, change it
n->wtext.display_baseline=n->wtext.current_line;
if (n->wtext.current_line!=tln_t) // If there are still lines left, free up the deleted lines storage
{
free(tln_t->the_text); //free up the char array.
free(tln_t); //free up the line structure
}else{ // Don't free the last line, just set it as empty otherwise there is nowhere to put characters that we type
n->wtext.current_line->eof_line=0;
n->wtext.current_line->the_text[0]='\0';
}
if (n->wtext.current_column>n->wtext.current_line->eof_line)
n->wtext.current_column=n->wtext.current_line->eof_line;
graf_mouse(M_OFF,NULL);
TW_display();
graf_mouse(M_ON,NULL);
}else{ // Delete on it's own does delete char under cursor
if (n->wtext.current_column<n->wtext.current_line->eof_line) // Not at end of line yet, so simply shuffle things back to erase current character.
{
for(p=n->wtext.current_column; p<n->wtext.current_line->eof_line; p++)
n->wtext.current_line->the_text[p]=n->wtext.current_line->the_text[p+1];
n->wtext.current_line->eof_line--;
n->wtext.current_line->the_text[n->wtext.current_line->eof_line]='\0';
graf_mouse(M_OFF,NULL);
TW_display();
graf_mouse(M_ON,NULL);
}else{ // Otherwise, try to append next line to this one
if (n->wtext.current_line->next)
{
if (n->wtext.current_line->eof_line+n->wtext.current_line->next->eof_line < n->wtext.max_columns)
{
tln_t=n->wtext.current_line->next;
tmp=n->wtext.current_line->the_text+(n->wtext.current_line->eof_line); // Tag next line onto the end off this line
sprintf(tmp,"%s",tln_t->the_text);
n->wtext.current_line->eof_line=strlen(n->wtext.current_line->the_text);
n->wtext.current_line->the_text[n->wtext.current_line->eof_line]='\0';
n->wtext.current_line->next=tln_t->next; // detatch line from list
if (tln_t->next)
tln_t->next->prev=n->wtext.current_line;
free(tln_t->the_text); //free up the char array.
free(tln_t); //free up the line structure
graf_mouse(M_OFF,NULL);
TW_display();
graf_mouse(M_ON,NULL);
}
}
}
}
return TRUE;
break;
}
// If we get to here, then we must just have a plain character typed.
c=(char)(kc_key&255); // Convert scan code into ASCII character.
if (n->wtext.current_line->eof_line<n->wtext.max_columns) // Insert character into line (if line isn't full).
{
if (n->wtext.current_column!=n->wtext.current_line->eof_line) // If not at end of line, insert a space for the character
{
for(p=n->wtext.current_line->eof_line; p>n->wtext.current_column; p--)
n->wtext.current_line->the_text[p]=n->wtext.current_line->the_text[p-1];
}
n->wtext.current_line->the_text[n->wtext.current_column]=c;
n->wtext.current_column++;
n->wtext.current_line->eof_line++;
n->wtext.current_line->the_text[n->wtext.current_line->eof_line]='\0';
graf_mouse(M_OFF,NULL);
TW_display();
graf_mouse(M_ON,NULL);
return TRUE; // Consume
}
return TRUE; // Consume
}